/*
 arm.c
 
 http://code.google.com/p/armstorm/
 distorm at gmail dot com
 Copyright (C) 2012 Gil Dabah
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>
*/

#include "armstorm.h"
#include "common.h"

static _Condition decompose_arm_condition(unsigned long instruction)
{
	return (instruction & COND_BIT_MASK) >> COND_BIT_POS;
}

_DecodeResult decompose_arm(_DecomposeInfo* info)
{
	unsigned int instsNo = 0;
    unsigned long instruction;
    _DInst* pdi;

    while ((info->codeLength >= 4) && (instsNo < info->maxInstructions)) {
		/* Read current instruction from stream. */
        instruction = read_long(info->code, info->endianity);
        
		/* Set local pointer to current instruction, memset it to
		 *    zero to set an initial state. */
        pdi = &info->instructions[instsNo];
		memset((void*)pdi, 0, sizeof(_DInst));
		pdi->flags |= FLAG_BIG_INST;
		
		/* Find condition of the instruction, currently set
		 *    instruction as invalid if find one with all bits
		 *    set, or INVALID case. */
        pdi->cond = decompose_arm_condition(instruction);
		if(pdi->cond == INVALID)
		{
			pdi->flags |= FLAG_INVALID;
			pdi->opcode = I_UNDEFINED;
		}
		
		// pdi->address = info->address;
        // if (!decompose_thumb_instruction(instruction, nextInstruction, pdi)) {
            // pdi->flags = FLAG_INVALID;
            // pdi->opcode = I_UNDEFINED;
            // /* Opcode wasn't found. */
        // }
		pdi->address = info->address;
        
        /* Determine increment count */
        instsNo += 1;
        info->address += 4;
        info->code += 4;
        info->codeLength -= 4;
    }
    
    /* Update number of decoded instructions. */
    info->decodedInstructionsCount = instsNo;
    	
    return DECRES_SUCCESS;
}